from numpy import *
import operator
from os import listdir

def createDataSet():
    group = array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])
    labels = ['A','A','B','B']
    return group, labels

'''
    sqrt (（x-x0)^2 +(y -y0)^2 )
'''
def classify0(inX,dataSet, labels, k):
    '''求inX和dataSet中数据的距离'''
    dataSetSize = dataSet.shape[0] #一维长度
    '''按dataSet一维长度扩展inX 然后做减法求差值'''
    diffMat = tile(inX,(dataSetSize,1)) - dataSet 
    sqDiffMat = diffMat ** 2 #求平方
    sqDistances  = sqDiffMat.sum(axis = 1) #求和 x^2 +y^2
    distances = sqDistances ** 0.5 #开方
    sortedDistIndicies = distances.argsort()  #按升序将索引排序 
    classCount = {}  #分类数量统计临时键值对
    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1),reverse=True)
    return sortedClassCount[0][0]

''' 读取文件 转换为特征矩阵及分类标签 '''
def file2matrix(filename):
    fr = open(filename)
    numberOfLines = len(fr.readlines())  #文件最大行数
    returnMat = zeros((numberOfLines,3)) #创建以0填充的 numberOfLines * 3 的矩阵 
    classLabelVector = []   #标签数组
    fr = open(filename)
    index = 0
    for line in fr.readlines():
        line = line.strip()     #前后去空格
        listFromLine = line.split('\t')      #按制表符分割
        returnMat[index,:] = listFromLine[0:3] 
        #print( listFromLine[-1] )
        classLabelVector.append(int(listFromLine[-1])) #添加label
        index += 1
    return returnMat, classLabelVector

'''标准化输入  newVal = (oldVal - min) / (max -min) '''
def autoNorm(dataSet):
    minVals = dataSet.min(0) #抽取列最小值 
    maxVals = dataSet.max(0) #抽取列最大值
    ranges = maxVals - minVals #每行的最大和最小值差组成的数组
    normDataSet = zeros(shape(dataSet)) #构建一个0组成的和原始数组一致的数组
    m = dataSet.shape[0] #原始数组第一维长度
    normDataSet = dataSet - tile(minVals, (m,1)) #将minVals一维数组扩展成与原始数组统一的维度，然后做减法
    normDataSet = normDataSet / tile(ranges,(m,1)) #将ranges扩展为与原始数组统一的维度，然后相除
    return normDataSet,ranges, minVals

def datingClassTest():
    hotRatio = 0.50
    datingDataMat, datingLabels = file2matrix('CH2/datingTestSet2.txt') #读取文件，解析成特征矩阵和对应的标签素组
    normMat, ranges, minVals = autoNorm(datingDataMat)  #归一化特征值
    m = normMat.shape[0]
    numTestVecs = int(m * hotRatio) #样本数据条数
    errorCount = 0.0
    for i in range(numTestVecs):
        '''
            normMat[numTestVecs:m,:] 样本数据剩余50%作为训练数据
            datingLabels[numTestVecs:m] 样本数据剩余50%对应的分类标签
            10 取前10个相似的分类
        '''
        classifierResult = classify0(normMat[i,:],normMat[numTestVecs:m,:]  ,datingLabels[numTestVecs:m]  ,10 )
        print("the classifier came back with: %d, the real answer is: %d" %(classifierResult, datingLabels[i] ) )
        if classifierResult != datingLabels[i]:
            errorCount = errorCount + 1.0  #标记错误
    print("the total error rate is: %f" %( errorCount/float(numTestVecs)))

''' 测试kNN 
datingClassTest()
'''